package org.springframework.context.support;

import javafx.application.Application;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.*;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @className：AbstractApplicationContext
 * @description:
 * @author: xiaohuihui
 * @createDate: 2021/8/29
 * @version: 1.0
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {




    static {
        //先加载ContextClosedEvent类，以避免WebLogic 8.1中应用程序关闭时出现奇怪的类加载器问题(达斯汀·伍兹报道。）
        ContextClosedEvent.class.getName();
    }

    /**
     * 此类的记录器可用于子类
     */
    protected final Log logger = LogFactory.getLog(getClass());

    /**
     * 此上下文唯一的ID（如果有）
     */
    private String id = ObjectUtils.identityToString(this);

    /**
     * 显示名称
     */
    private String displayName = ObjectUtils.identityToString(this);

    /**
     * 父上下文
     */
    @Nullable
    private ApplicationContext parent;


    /**
     * 此上下文使用的环境
     */
    @Nullable
    private ConfigurableEnvironment environment;


    /**
     * BeanFactoryPostProcessor在刷新时应用
     */
    private final List<BeanFactoryPostProcessor> beanFactoryProcessors = new ArrayList<>();

    /**
     * 此上下文启动时的系统时间（毫秒为单位）
     */
    private long startupDate;


    /**
     * 指示此上下文当前是否处于活动状态的标志
     */
    private final AtomicBoolean active = new AtomicBoolean();

    /**
     * 指示此上下文是否已关闭的标志
     */
    private final AtomicBoolean closed = new AtomicBoolean();

    /**
     * "刷新"和“销毁”的同步监视器
     */
    private final Object startupShutdownMonitor = new Object();

    /**
     * 对JVM关闭钩子的引用（如果已注册）
     */
    @Nullable
    private Thread shutdownHook;

    /**
     * 此上下文使用的ResourcePatternResolver
     */
    private ResourcePatternResolver resourcePatternResolver;

    /**
     * LifecycleProcessor用于在此上下文中管理bean的生命周期
     */
    @Nullable
    private LifecycleProcessor lifecycleProcessor;

    /**
     * 我们将此接口的实现委托给MessageSource
     */
    @Nullable
    private MessageSource messageSource;

    /**
     * 用于事件发布的助手类
     */
    @Nullable
    private ApplicationEventMulticaster applicationEventMulticcaster;


    /**
     * 静态指定的侦听器
     */
    private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

    /**
     * 刷新前注册的本地监听器
     */
    @Nullable
    private Set<ApplicationListener<?>> earlyApplicationListeners;

    /**
     * 在多播器设置之前发布的ApplicationEvent
     */
    @Nullable
    private Set<ApplicationEvent> earlyApplicationEvents;



    /**
     * 创建一个没有父级的新的AbstractApplicationContext
     */
    public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }
    /**
     * 使用给定的父上下文创建一个新的AbstractApplicationContext
     * @param parent
     */
    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
        this();
        setParent(parent);
    }



    @Override
    public void setParent(ApplicationContext parent) {
        this.parent = parent;
        if (parent != null){
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment){
                getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
            }
        }
    }

    @Override
    public Environment getEnvironment() {

        if (this.environment == null){
            this.environment = crcreateEnvironment();
        }
            return null;
    }

    protected ConfigurableEnvironment crcreateEnvironment() {
        return new StandardEnvironment();
    }

    public ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }


}
